# utils/logger.py
import logging
import os
import sys
import inspect
import functools
from typing import Optional

from config import settings

# 添加项目根目录到Python路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# 🌟 新增：定义自定义日志级别
FILE_LOG_LEVEL = 25  # 介于 INFO(20) 和 WARNING(30) 之间
logging.addLevelName(FILE_LOG_LEVEL, 'FILELOG')


class AgentLogger:
    """统一的日志模块，包含模块名、行号、时间戳等属性"""

    def __init__(self, name: str, log_file: Optional[str] = None):
        self.logger = logging.getLogger(name)
        self.logger.setLevel(getattr(logging, settings.LOG_LEVEL))

        # 🌟 关键修改：避免重复添加处理器，依赖根logger的配置
        # 只在没有处理器且需要特殊配置时才添加
        if not self.logger.handlers and (log_file or settings.LOG_FILE):
            # 只有在明确指定日志文件时才添加文件处理器
            log_path = log_file or settings.LOG_FILE
            if log_path:
                # 确保日志目录存在
                log_dir = os.path.dirname(log_path)
                if log_dir and not os.path.exists(log_dir):
                    os.makedirs(log_dir)

                # 创建日志格式
                formatter = logging.Formatter(
                    '%(asctime)s - %(name)s - %(levelname)s - %(location_info)s - %(message)s'
                )

                # 控制台处理器
                console_handler = logging.StreamHandler(sys.stdout)
                console_handler.setFormatter(formatter)
                self.logger.addHandler(console_handler)

                # 文件处理器（全量日志）
                file_handler = logging.FileHandler(log_path, encoding='utf-8')
                file_handler.setFormatter(formatter)
                self.logger.addHandler(file_handler)
        else:
            # 🌟 确保logger传播到根logger，这样就能使用main.py中的选择性文件处理器
            self.logger.propagate = True

    def _log_with_caller_info(self, level: int, message: str):
        """记录带有调用者信息的日志"""
        try:
            # 获取调用栈信息
            stack = inspect.stack()
            # 跳过当前函数和日志方法调用帧，获取实际调用者信息
            if len(stack) > 2:
                caller_frame = stack[2]
                filename = os.path.basename(caller_frame.filename)
                lineno = caller_frame.lineno
                func_name = caller_frame.function

                # 格式化位置信息
                location_info = f"{filename}:{func_name}:{lineno}"
                formatted_message = message
            else:
                # 如果无法获取调用栈信息，使用默认格式
                location_info = "unknown:unknown:0"
                formatted_message = message

            # 创建并处理日志记录，使用完整的参数列表消除编辑器警告
            record = self.logger.makeRecord(
                self.logger.name,  # name
                level,  # level
                filename,  # fn (filename)
                lineno,  # lno (line number)
                message,  # msg
                (),  # args (empty tuple for no args)
                None,  # exc_info
                func_name,  # func
                None,  # extra
                None  # sinfo
            )
            # 添加自定义的位置信息字段
            record.location_info = location_info
            self.logger.handle(record)
        except Exception as e:
            # 如果获取调用栈信息失败，回退到基本日志记录
            self.logger.log(level, message)

    def debug(self, message: str):
        self._log_with_caller_info(logging.DEBUG, message)

    def info(self, message: str):
        self._log_with_caller_info(logging.INFO, message)

    def warning(self, message: str):
        self._log_with_caller_info(logging.WARNING, message)

    def error(self, message: str):
        self._log_with_caller_info(logging.ERROR, message)

    def critical(self, message: str):
        self._log_with_caller_info(logging.CRITICAL, message)

    # 🌟 新增：文件日志方法
    def file_log(self, message: str):
        """记录到文件的日志（同时也会显示在控制台）"""
        self._log_with_caller_info(FILE_LOG_LEVEL, message)


def get_logger(name: str) -> AgentLogger:
    """获取日志记录器的工厂方法"""
    return AgentLogger(name)


# 🌟 新增：装饰器和快捷函数
def file_log(message_template: str = None):
    """
    装饰器：将被装饰函数的执行记录到文件

    Args:
        message_template: 自定义消息模板，可以使用 {function} 和 {result} 占位符
    """

    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            # 获取调用模块的logger
            frame = inspect.currentframe().f_back
            module_name = frame.f_globals.get('__name__', 'unknown')
            logger = logging.getLogger(module_name)

            func_name = func.__name__

            # 默认消息模板
            if message_template is None:
                start_message = f"开始执行: {func_name}"
                success_message = f"完成执行: {func_name}"
                error_message = f"执行失败: {func_name}"
            else:
                start_message = message_template.format(function=func_name, result="开始")
                success_message = message_template.format(function=func_name, result="完成")
                error_message = message_template.format(function=func_name, result="失败")

            # 记录开始
            logger.log(FILE_LOG_LEVEL, start_message)

            try:
                result = func(*args, **kwargs)
                # 记录成功完成
                logger.log(FILE_LOG_LEVEL, success_message)
                return result
            except Exception as e:
                # 记录失败
                logger.log(FILE_LOG_LEVEL, f"{error_message} - 错误: {str(e)}")
                raise

        return wrapper

    return decorator


def log_to_file(message: str):
    """
    快捷函数：直接记录消息到文件

    Args:
        message: 要记录的消息
    """
    frame = inspect.currentframe().f_back
    module_name = frame.f_globals.get('__name__', 'unknown')
    logger = logging.getLogger(module_name)
    logger.log(FILE_LOG_LEVEL, message)